package com.ruoyi.core.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.*;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * @Description:
 * @Company: 北京卡拉卡尔股份技术有限公司
 * @Author: Darren Ho
 * @Date: 11/15/2020 18:44
 */

public class DefaultScheduledTaskRegistrar implements DisposableBean {

    private final Logger logger = LoggerFactory.getLogger(DefaultScheduledTaskRegistrar.class);


    private TaskScheduler taskScheduler;


    private Map<String, ScheduledTask> tasks = new ConcurrentHashMap<>();

    public DefaultScheduledTaskRegistrar(TaskScheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
    }


    /**
     * 添加任务
     *
     * @param taskId
     * @param triggerTask
     */
    public void addTriggerTask(String taskId, TriggerTask triggerTask) {
        if (tasks.containsKey(taskId)) {
            throw new SchedulingException("the taskId[" + taskId + "] was added.");
        }
        logger.info("add task [{}]", taskId);
        ScheduledTask scheduledTask = new ScheduledTask(triggerTask);
        scheduledTask.future = taskScheduler.schedule(triggerTask.getRunnable(), triggerTask.getTrigger());
        tasks.put(taskId, scheduledTask);
    }

    /**
     * 取消任务
     *
     * @param taskId
     */
    public void cancelTriggerTask(String taskId) {
        ScheduledFuture<?> future = tasks.get(taskId).future;
        if (future != null) {
            logger.info("cancel task [{}]", taskId);
            future.cancel(true);
        }
        tasks.remove(taskId);

    }

    /**
     * 重置任务
     *
     * @param taskId
     * @param triggerTask
     */
    public void resetTriggerTask(String taskId, TriggerTask triggerTask) {
        logger.info("reset task [{}]", taskId);
        cancelTriggerTask(taskId);
        addTriggerTask(taskId, triggerTask);
    }

    /**
     * 任务编号
     *
     * @return
     */
    public Set<String> taskIds() {
        return tasks.keySet();
    }

    /**
     * 是否存在任务
     *
     * @param taskId
     * @return
     */
    public boolean hasTask(String taskId) {
        return this.tasks.containsKey(taskId);
    }


    @Override
    public void destroy() throws Exception {
        tasks.keySet().forEach(this::cancelTriggerTask);
        ThreadPoolTaskScheduler threadPoolTaskScheduler = (ThreadPoolTaskScheduler) taskScheduler;
        threadPoolTaskScheduler.destroy();
    }

    public final static class ScheduledTask {

        private final Task task;

        @Nullable
        volatile ScheduledFuture<?> future;


        public ScheduledTask(Task task) {
            this.task = task;
        }


        /**
         * Return the underlying task (typically a {@link CronTask},
         * {@link FixedRateTask} or {@link FixedDelayTask}).
         *
         * @since 5.0.2
         */
        public Task getTask() {
            return this.task;
        }

        /**
         * Trigger cancellation of this scheduled task.
         */
        public void cancel() {
            ScheduledFuture<?> future = this.future;
            if (future != null) {
                future.cancel(true);
            }
        }


    }
}
